#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QFileInfoList>
#include <QProcess>
#include <QDebug>
#include <QTextStream>
#include <QDateTime>
QTextStream stm(stderr);
QStringList enumRemotes()
{
	stm<<"\nEnum remotes:\n";
	stm.flush();
	QProcess p;
	p.setProgram("git");
	QStringList l;
	l<< "remote";
	p.setArguments(l);
	p.start();
	p.waitForFinished(-1);
	QByteArray outE = p.readAllStandardError();
	QByteArray outS = p.readAllStandardOutput();
	fputs(outE.toStdString().c_str(),stderr);
	fflush(stderr);
	fputs(outS.toStdString().c_str(),stdout);
	fflush(stdout);
	QStringList res = QString::fromUtf8(outS).split("\n",Qt::SkipEmptyParts);
	QStringList ret ;
	foreach (QString s, res)
	{
		QString v = s.remove("*").trimmed();
		if (v.size())
			ret << v;
	}
	return ret;
}

QStringList enumBranchs()
{
	stm<<"\nEnum branchs:\n";
	stm.flush();
	QProcess p;
	p.setProgram("git");
	QStringList l;
	l<< "branch";
	p.setArguments(l);
	p.start();
	p.waitForFinished(-1);
	QByteArray outE = p.readAllStandardError();
	QByteArray outS = p.readAllStandardOutput();
	fputs(outE.toStdString().c_str(),stderr);
	fflush(stderr);
	fputs(outS.toStdString().c_str(),stdout);
	fflush(stdout);
	QStringList res = QString::fromUtf8(outS).split("\n",Qt::SkipEmptyParts);
	QStringList ret ;
	foreach (QString s, res)
	{
		QString v = s.remove("*").trimmed();
		if (v.size())
			ret << v;
	}
	return ret;
}

bool checkOut(QString branch)
{
	stm<<"\nCheckout branch:\n"<<branch<<"\n";
	stm.flush();
	QProcess p;
	p.setProgram("git");
	QStringList l;
	l<< "checkout";
	l<<branch;
	p.setArguments(l);
	p.start();
	p.waitForFinished(-1);
	QByteArray outE = p.readAllStandardError();
	QByteArray outS = p.readAllStandardOutput();
	fputs(outE.toStdString().c_str(),stderr);
	fflush(stderr);
	fputs(outS.toStdString().c_str(),stdout);
	fflush(stdout);
	if (outE.startsWith("error:"))
		return false;
	return true;
}

bool pullRemotes(QString remote, QString branch, bool * upToDate)
{
	stm<<"\ngit pull "<<remote<<" "<<branch<<"\n";
	stm.flush();
	QProcess p;
	p.setProgram("git");
	QStringList l;
	l<< "pull";
	l<<remote;
	l<<branch;
	p.setArguments(l);
	p.start();
	p.waitForFinished(-1);
	QByteArray outE = p.readAllStandardError();
	QByteArray outS = p.readAllStandardOutput();

	if (outE.contains("Already up to date") || outS.contains("Already up to date"))
		*upToDate  =true;
	else
		*upToDate  =false;
	fputs(outE.toStdString().c_str(),stderr);
	fflush(stderr);
	fputs(outS.toStdString().c_str(),stdout);
	fflush(stdout);
	if (outE.startsWith("error:"))
	{
		*upToDate  =true;
		return false;
	}
	return true;
}

bool pushRemotes(QString remote, QString branch)
{
	stm<<"\ngit push "<<remote<<" "<<branch<<"\n";
	stm.flush();
	QProcess p;
	p.setProgram("git");
	QStringList l;
	l<< "push";
	l<<remote;
	l<<branch;
	p.setArguments(l);
	p.start();
	p.waitForFinished(-1);
	QByteArray outE = p.readAllStandardError();
	QByteArray outS = p.readAllStandardOutput();
	fputs(outE.toStdString().c_str(),stderr);
	fflush(stderr);
	fputs(outS.toStdString().c_str(),stdout);
	fflush(stdout);
	if (outE.startsWith("error:"))
		return false;
	return true;
}

int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	QString wkd = a.applicationDirPath();
	QDir dir;
	if (argc>1)
		wkd = QString(argv[1]);
	QDir d(wkd);
	QFileInfoList lstDirs = d.entryInfoList(QDir::AllEntries|QDir::NoDotAndDotDot);
	QString strDtm = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
	stm<<"\n\n<<<<<<<<<< "<<strDtm<<" >>>>>>>>>"<<"\n";
	foreach (QFileInfo info, lstDirs)
	{
		if (!info.isDir())
			continue;
		if (!QFileInfo::exists(info.absoluteFilePath()+"/.git"))
			continue;
		stm<<"\n=========  "<<info.fileName()<<"  =========  \n";
		stm.flush();
		//Enum remotes
		QDir dir;
		QString strOldCurrDir = dir.currentPath();
		dir.setCurrent(info.absoluteFilePath());
		QStringList rmts = enumRemotes();

		//Enum branchs
		QStringList branchs = enumBranchs();

		//foreach branch, pull from each remotes
		foreach(QString br, branchs)
		{
			if (!checkOut(br))
				break;
			//pull
			bool upToDate = true;
			foreach(QString rt, rmts)
			{
				bool updt = true;
				pullRemotes(rt,br,&updt);
				if (!updt)
					upToDate = false;
			}
			//push
			if (!upToDate)
			{
				foreach(QString rt, rmts)
				pushRemotes(rt,br);
			}
		}
		dir.setCurrent(strOldCurrDir);
	}

	a.processEvents();
	return 0;
}
